﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Telerik.WinControls.UI;

namespace UnigenReport.Form
{
    public partial class ucInvoiceEdit : UserControl
    {
        public bool modifySaved = false;
        private Invoice refData;
        private UnigenDataContext db;
        private bool action;//True: Add, False: Update
        private string IdPrefix = "UHAN_INV";

        #region Thiết lập

        public ucInvoiceEdit()
        {
            InitializeComponent();
            //Phân quyền
            if (Variables.UserRoleID == 0) btnSave.Enabled = false;
            SetEvent();

            action = true;
        }

        /// <summary>
        /// Hàm show ra ngoài cho việc update
        /// </summary>
        /// <param name="refData"></param>
        /// <returns></returns>
        public ucInvoiceEdit ForUpdate(Invoice obj)
        {
            refData = obj;
            action = false;
            return this;
        }

        /// <summary>
        /// Khai báo các sự kiện
        /// </summary>
        private void SetEvent()
        {
            Load += OnLoad;
            this.btnSave.Click += new System.EventHandler(this.btnSave_Click);
            this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click);
            this.btnAddShippingRequest.Click += new EventHandler(btnAddShippingRequest_Click);
            this.btnCalculateInvoice.Click += new System.EventHandler(this.btnCalculateInvoice_Click);
            
            this.cboBillTo.KeyDown += new System.Windows.Forms.KeyEventHandler(this.cboBillTo_KeyDown);
            this.cboShipTo.KeyDown += new System.Windows.Forms.KeyEventHandler(this.cboShipTo_KeyDown);
            this.cboInvoiceNoIndex.ValueChanged += new System.EventHandler(this.cboInvoiceNoIndex_ValueChanged);
            this.cboShipAccount.SelectedIndexChanged += new EventHandler(cboShipAccount_SelectedIndexChanged);
            this.cboShipTo.SelectedIndexChanged += new System.EventHandler(this.cboShipTo_SelectedIndexChanged);
            this.cboBillTo.SelectedIndexChanged += new System.EventHandler(this.cboBillTo_SelectedIndexChanged);
            
            this.chkPLTypeMix.ToggleStateChanged += new Telerik.WinControls.UI.StateChangedEventHandler(this.chkPLTypeCarton_ToggleStateChanged);
            this.chkPLTypePallet.ToggleStateChanged += new Telerik.WinControls.UI.StateChangedEventHandler(this.chkPLTypeCarton_ToggleStateChanged);
            this.chkPLTypeCarton.ToggleStateChanged += new Telerik.WinControls.UI.StateChangedEventHandler(this.chkPLTypeCarton_ToggleStateChanged);
            
            this.grvInvoiceDetail.CellValueChanged += new Telerik.WinControls.UI.GridViewCellEventHandler(this.grvInvoiceDetail_CellValueChanged);
            this.grvInvoicePL.CellValueChanged += new Telerik.WinControls.UI.GridViewCellEventHandler(this.grvInvoicePL_CellValueChanged);
        }
        
        /// <summary>
        /// Hàm load form
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnLoad(object sender, EventArgs e)
        {
            //Load default
            SetDefault();
        }
        
        /// <summary>
        /// Thiết lập các giá trị mặc định của form
        /// </summary>
        private void SetDefault()
        {
            txtDate.Value = DateTime.Now;

            //Product
            db = new UnigenDataContext();
            sourceShipVia.DataSource = db.ShipVias.OrderBy(p=>p.Name).ToList();
            sourceShipAccount.DataSource = db.ShipAccounts.OrderBy(p=>p.Name).ToList();
            sourceShipTerm.DataSource = db.ShipTerms.OrderBy(p=>p.Name).ToList();
            sourceBillTo.DataSource = db.ShipAddresses.Where(p => p.Type == 0 && p.Active == true).ToList();            
            sourceShipTo.DataSource = db.ShipAddresses.Where(p => p.Type == 1 && p.Active == true).OrderBy(p => p.Name).ToList();
            sourcePalletStandard.DataSource = db.PalletStandards.OrderBy(p => p.CartonTypeId).ToList();

            //Id
            GetInvoiceId();

            //Bind dữ liệu chính
            BindData();
        }

        /// <summary>
        /// Lấy dữ liệu chính
        /// </summary>
        private void BindData()
        {
            try
            {
                //Data bind
                if (refData != null)
                {
                    db = new UnigenDataContext();
                    pnlTitle.Text = "SỬA ĐỔI THÔNG TIN INVOICE \n (Chỉ được phép chọn thêm, không thể xóa những Shipping Request đã có)";

                    #region Invoice
                    txtDate.Value = refData.Date ?? DateTime.Now;                    
                    cboShipAccount.Text = refData.ShippingAccount;
                    var shipAcc = (sourceShipAccount.DataSource as List<ShipAccount>).SingleOrDefault(p => p.Value == refData.ShippingAccountValue.Trim()
                        && p.Name == refData.ShippingAccount);
                    if (shipAcc != null)
                        cboShipAccount.SelectedValue = shipAcc.AccountId;
                    cboShipVia.Text = refData.ShipVia;
                    cboShipTerm.Text = refData.ShipTerm;
                    txtTracking.Text = refData.Tracking;

                    cboBillTo.Text = refData.BillToName;
                    txtBillToName.Text = refData.BillToName;
                    txtBillToAddress.Text = refData.BillToAddress;
                    txtBillToPhone.Text = refData.BillToPhone;
                    txtBillToFax.Text = refData.BillToFax;
                    cboShipTo.Text = refData.ShipToName;
                    txtShipToName.Text = refData.ShipToName;
                    txtShipToAddress.Text = refData.ShipToAddress;
                    txtShipToPhone.Text = refData.ShipToPhone;
                    txtShipToFax.Text = refData.ShipToFax;

                    if (refData.Currency.Equals("USD"))
                        chkCurrencyUSD.IsChecked = true;
                    else
                        chkCurrencyVND.IsChecked = true;

                    if (refData.PackingType == 0)
                        chkPLTypeCarton.IsChecked = true;
                    else if (refData.PackingType == 1)
                        chkPLTypePallet.IsChecked = true;
                    else
                        chkPLTypeMix.IsChecked = true;

                    chkPackingByWO.Checked = refData.PackingMode == 1;

                    #endregion

                    #region Request

                    //Thay đổi Ship request
                    var requestIds = refData.RequestIds.Split(',').ToList();
                    var lstShippingRequest = db.ShippingRequests.Where(p => requestIds.Contains(p.RequestId.ToString())).ToList();
                    sourceShippingRequest.DataSource = lstShippingRequest;

                    #endregion

                    #region Detail
                    sourceInvoiceDetail.DataSource = db.InvoiceDetails.Where(p => p.InvoiceId == refData.InvoiceId).ToList();
                    #endregion

                    #region Packing list
                    sourceInvoidePL.DataSource = db.InvoicePackingLists.Where(p => p.InvoiceId == refData.InvoiceId).ToList();
                    #endregion

                    Common.SetNo(grvShippingRequest);
                    Common.SetNo(grvInvoiceDetail);
                    Common.SetNo(grvInvoicePL);
                    cboBillTo.Enabled = false;
                    cboShipTo.Enabled = false;
                    grvShippingRequest.AllowDeleteRow = false;

                    if (refData.Approve ?? false)
                    {
                        btnSave.Enabled = false;
                        pnlTitle.Text = "XEM THÔNG TIN INVOICE \n (Không thể sửa đổi do Invoice đã được xác nhận)";
                    }
                    if (!action && sourceShippingRequest.Count == 0)
                    {
                        btnCalculateInvoice.Enabled = false;
                        grvShippingRequest.TableElement.Text = "Các Shipping request liên quan đã bị xóa. Tuy nhiên dữ liệu Invoice vẫn được lưu!";
                    }
                }
                else
                {
                    pnlTitle.Text = "THÊM MỚI INVOICE";
                    grvShippingRequest.TableElement.Text = "Thêm Shipping request, hoặc loại bỏ bằng nút DELETE";
                }
            }
            catch (Exception ex)
            {
                Common.ShowErrorMess("BindData - " + ex.Message);
            }
        }

        private void GetInvoiceId()
        {
            try
            {
                db = new UnigenDataContext();
                var invoice = new Invoice();
                if (action)
                    invoice = db.Invoices.Count() > 0 ? db.Invoices.ToList().Last() : null;
                else
                    invoice = refData;

                if (invoice != null)
                {
                    var id = Convert.ToInt32(invoice.InvoiceNo.Replace(IdPrefix, String.Empty));
                    cboInvoiceNoIndex.Value = action ? id + 1 : id;
                }
                else
                    cboInvoiceNoIndex.Value = 1;
            }
            catch (Exception ex)
            {
                Common.ShowErrorMess("GetInvoiceId - " + ex.Message);
            }
        }

        #endregion

        #region Hàm

        private void Save()
        {
            db = new UnigenDataContext();
            try
            {
                #region Check valid
                if (String.IsNullOrEmpty(txtInvoiceNo.Text.Trim()))
                {
                    Common.ShowNoticeMess("Nhập số Invoice!");
                    return;
                }
                if(db.Invoices.Count(p=>p.InvoiceNo == txtInvoiceNo.Text.Trim()) > 0 && action)
                {
                    Common.ShowNoticeMess("Số Invoice đã tồn tại!");
                    return;
                }
                if (sourceInvoiceDetail.Count == 0 || sourceInvoidePL.Count == 0)
                {
                    Common.ShowNoticeMess("Chưa có số liệu!");
                    return;
                }
                #endregion

                db.Connection.Open();
                db.Transaction = db.Connection.BeginTransaction();

                #region Invoice
                var invoiceNo = txtInvoiceNo.Text.Trim();
	            var date = txtDate.Value;
	            var billToName = txtBillToName.Text.Trim();
	            var billToAddress = txtBillToAddress.Text.Trim();
	            var billToPhone = txtBillToPhone.Text.Trim();
	            var billToFax = txtBillToFax.Text.Trim();
	            var shipToName = txtShipToName.Text.Trim();
	            var shipToAddress = txtShipToAddress.Text.Trim();
	            var shipToPhone = txtShipToPhone.Text.Trim();
	            var shipToFax = txtShipToFax.Text.Trim();
                var shippingAccount = cboShipAccount.Text;
                var shippingAccountValue = sourceShipAccount.Current != null ? (sourceShipAccount.Current as ShipAccount).Value : String.Empty;
	            var tracking = txtTracking.Text.Trim();
	            var shipVia = cboShipVia.Text;
	            var shipTerm = cboShipTerm.Text;
	            var currency = chkCurrencyUSD.IsChecked ? chkCurrencyUSD.Text : chkCurrencyVND.Text;
	            var requestIds = String.Join(",",(sourceShippingRequest.DataSource as List<ShippingRequest>).Select(p=>p.RequestId).ToArray());
                //packing mode
                var packingMode = chkPackingByWO.Checked ? 1 : 0;
                //Packing type
                var packingType = 0;
                if (chkPLTypePallet.IsChecked)
                    packingType = 1;
                else if (chkPLTypeMix.IsChecked)
                    packingType = 2;

                var invoice = new Invoice();
                if(action)
                {

                    invoice.InvoiceNo = invoiceNo;
	                invoice.Date = date;
	                invoice.BillToName = billToName;
	                invoice.BillToAddress = billToAddress;
	                invoice.BillToPhone = billToPhone;
	                invoice.BillToFax = billToFax;
	                invoice.ShipToName = shipToName;
	                invoice.ShipToAddress = shipToAddress;
	                invoice.ShipToPhone = shipToPhone;
	                invoice.ShipToFax = shipToFax;
	                invoice.ShippingAccount = shippingAccount;
                    invoice.ShippingAccountValue = shippingAccountValue;
	                invoice.Tracking = tracking;
	                invoice.ShipVia = shipVia;
	                invoice.ShipTerm = shipTerm;
	                invoice.Currency = currency;
                    invoice.PackingType = packingType;
                    invoice.PackingMode = packingMode;
	                invoice.RequestIds = requestIds;
	                invoice.Approve = false;
	                invoice.Active = true;

                    db.Invoices.InsertOnSubmit(invoice);
                }
                else
                {
                    //Cập nhật thông tin
                    invoice = db.Invoices.SingleOrDefault(pt => pt.InvoiceId == refData.InvoiceId);
                    if (invoice != null)
                    {
                        invoice.InvoiceNo = invoiceNo;
	                    invoice.Date = date;
	                    invoice.BillToName = billToName;
	                    invoice.BillToAddress = billToAddress;
	                    invoice.BillToPhone = billToPhone;
	                    invoice.BillToFax = billToFax;
	                    invoice.ShipToName = shipToName;
	                    invoice.ShipToAddress = shipToAddress;
	                    invoice.ShipToPhone = shipToPhone;
	                    invoice.ShipToFax = shipToFax;
                        invoice.ShippingAccount = shippingAccount;
                        invoice.ShippingAccountValue = shippingAccountValue;
	                    invoice.Tracking = tracking;
	                    invoice.ShipVia = shipVia;
	                    invoice.ShipTerm = shipTerm;
                        invoice.Currency = currency;
                        invoice.PackingType = packingType;
                        invoice.PackingMode = packingMode;
	                    invoice.RequestIds = requestIds;
                    }
                }

                //Submit 
                db.SubmitChanges();
                #endregion

                #region Detail

                //Xóa trc
                db.InvoiceDetails.DeleteAllOnSubmit(db.InvoiceDetails.Where(p => p.InvoiceId == invoice.InvoiceId));
                db.SubmitChanges();

                //Thêm sau
                List<InvoiceDetail> lstInvoiceDetail = new List<InvoiceDetail>();
                for (int i = 0; i < sourceInvoiceDetail.Count; i++)
                {
                    var item = sourceInvoiceDetail[i] as InvoiceDetail;
                    var copyItem = item.Clone();
                    copyItem.InvoiceId = invoice.InvoiceId;
                    lstInvoiceDetail.Add(copyItem);
                }
                db.InvoiceDetails.InsertAllOnSubmit(lstInvoiceDetail);
                db.SubmitChanges();

                #endregion

                #region Packing list

                //Xóa trc
                db.InvoicePackingLists.DeleteAllOnSubmit(db.InvoicePackingLists.Where(p => p.InvoiceId == invoice.InvoiceId));
                db.SubmitChanges();
                
                //Thêm sau
                List<InvoicePackingList> lstPackingList = new List<InvoicePackingList>();
                for (int i = 0; i < sourceInvoidePL.Count; i++)
                {
                    var item = sourceInvoidePL[i] as InvoicePackingList;
                    var copyItem = item.Clone();
                    copyItem.InvoiceId = invoice.InvoiceId;
                    lstPackingList.Add(copyItem);
                }
                db.InvoicePackingLists.InsertAllOnSubmit(lstPackingList);
                db.SubmitChanges();

                #endregion

                #region Shipping request
                foreach (var item in sourceShippingRequest.DataSource as List<ShippingRequest>)
                {
                    var changeSR = db.ShippingRequests.SingleOrDefault(p => p.RequestId == item.RequestId);
                    if (changeSR != null)
                        changeSR.Status = 1;
                }
                //Xác nhận
                db.SubmitChanges();
                #endregion

                //Commit trans
                db.Transaction.Commit();

                modifySaved = true;

                //Thông báo
                this.ParentForm.DialogResult = DialogResult.OK;
            }
            catch (Exception ex)
            {
                db.Transaction.Rollback();
                Common.ShowErrorMess("Save - " + ex.Message);
            }
        }

        #endregion

        #region Sự kiện

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
           if (keyData == Keys.Enter && !btnSave.Focused && !btnCancel.Focused && (cboBillTo.FocusedElement == null)
               && grvInvoiceDetail.FocusedElement == null && grvInvoicePL.FocusedElement == null)
            {
                Save();
            }
            if (keyData == Keys.Escape)
            {
                this.ParentForm.DialogResult = DialogResult.Cancel;
            }
            return base.ProcessCmdKey(ref msg, keyData);
        }

        private void btnSave_Click(object sender, EventArgs e)
        {          
            Save();
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.ParentForm.DialogResult = DialogResult.Cancel;
        }

        private void btnAddShippingRequest_Click(object sender, EventArgs e)
        {
            try
            {
                var currentShipTo =sourceShipTo.Current as ShipAddress;
                if (currentShipTo.ShipAddressId == 0)
                {
                    Common.ShowNoticeMess("Chưa chọn địa chỉ nhận!");
                    cboShipTo.Focus();
                    return;
                }
                if(sourceShippingRequest.Count == 0)
                    sourceShippingRequest.DataSource = new List<ShippingRequest>();
                var copySource = (sourceShippingRequest.DataSource as List<ShippingRequest>).ToList();
                var newItem = new Form.ucShippingRequest() { Dock = DockStyle.Fill }.Select(copySource);
                newItem.isCallFromInvoice = true;
                newItem.shipToId = currentShipTo.ShipAddressId;
                var ui = Common.CreateForm(newItem, String.Empty, 900, 600);

                if (ui.ShowDialog() == DialogResult.OK)
                {
                    foreach (var item in newItem.refData)
                        sourceShippingRequest.Add(item);
                    Common.SetNo(grvShippingRequest);
                }
            }
            catch (Exception ex)
            {
                Common.ShowErrorMess("btnAddShippingRequest_Click - " + ex.Message);
            }
        }
        
        private void btnCalculateInvoice_Click(object sender, EventArgs e)
        {
            try
            {
                db = new UnigenDataContext();

                #region Commercial invoice

                if (sourceShippingRequest.Count == 0)
                {
                    Common.ShowNoticeMess("Chọn Shipping Request!");
                    return;
                }

                var lstInvoiceDetail = new List<InvoiceDetail>();
                foreach (ShippingRequest item in (sourceShippingRequest.DataSource as List<ShippingRequest>))
                {
                    //Xem đã tồn tại hàng có cùng wo chưa? (khác request)
                    var duplicate = lstInvoiceDetail.SingleOrDefault(p => p.WO == item.WorldOrder.WO);
                    if (duplicate == null)
                    {
                        var invoiceDetail = new InvoiceDetail();
                        invoiceDetail.WO = item.WorldOrder.WO;
                        invoiceDetail.PO = item.WorldOrder.PO;
                        invoiceDetail.ProductCode = item.WorldOrder.Product.ProductCode;
                        invoiceDetail.ProductName = item.WorldOrder.Product.ProductName;
                        invoiceDetail.Unit = item.WorldOrder.Product.Unit.UnitName;
                        invoiceDetail.Quantity = item.Quantity;
                        invoiceDetail.Price = item.WorldOrder.Product.Cost;
                        invoiceDetail.ExportPrice = item.WorldOrder.Product.SalePrice;
                        invoiceDetail.MaterialPrice = (invoiceDetail.ExportPrice ?? 0) - (invoiceDetail.Price ?? 0);
                        invoiceDetail.Amount = invoiceDetail.Quantity * invoiceDetail.Price;
                        invoiceDetail.ExportAmount = invoiceDetail.Quantity * invoiceDetail.ExportPrice;
                        invoiceDetail.UhanCodeUsing = item.WorldOrder.Product.UhanCodeUsing;
                        
                        lstInvoiceDetail.Add(invoiceDetail);
                    }
                    else
                    {
                        duplicate.Quantity += item.Quantity;
                        duplicate.Amount = duplicate.Quantity * duplicate.Price;
                        duplicate.ExportAmount = duplicate.Quantity * duplicate.ExportPrice;
                    }
                }
                lstInvoiceDetail = lstInvoiceDetail.OrderBy(p => p.ProductCode).ThenBy(p=>p.WO).ToList();
                sourceInvoiceDetail.DataSource = lstInvoiceDetail;
                Common.SetNo(grvInvoiceDetail);

                #endregion

                #region Packing list
                //Lấy thông tin đóng gói
                var lstPackingStandard = db.PackingStandards.Where(p => lstInvoiceDetail.Select(x => x.ProductCode).ToList()
                                                                            .Contains(p.Product.ProductCode)).ToList();
                //Tạo list packing
                var lstPackingList = new List<InvoicePackingList>();
                
                #region Chia ra theo carton

                var lstProduct = chkPackingByWO.Checked
                    ? lstInvoiceDetail.Select(p => new PackingProduct() { ProductCode = p.ProductCode, WO = p.WO, Quantity = p.Quantity ?? 0 })
                    : lstInvoiceDetail.Select(p => new { ProductCode = p.ProductCode, Quantity = p.Quantity ?? 0 })
                        .GroupBy(p => p.ProductCode, (key, g) => new PackingProduct() { ProductCode = key, Quantity = g.Sum(x => x.Quantity) });

                if (!chkPackingByWO.Checked)
                {
                    #region Đóng gói theo hàng
                    //Chạy theo từng mặt hàng
                    foreach (var product in lstProduct)
                    {
                        //Thông tin đóng gói
                        var standard = lstPackingStandard.SingleOrDefault(p => p.Product.ProductCode == product.ProductCode);
                        if (standard == null) continue;
                        var productQtyPerShipBox = standard.QtyPerInnerBox * standard.QtyPerShippingBox;
                        var productWt = standard.WeightOfInnerBox / standard.QtyPerInnerBox;

                        //Lấy danh sách thông tin theo mặt hàng, xếp từ bé > lớn
                        var lstPackingByProduct = lstInvoiceDetail.Where(p => p.ProductCode == product.ProductCode).OrderBy(p => p.Quantity).ToList();

                        //Tổng lượng hàng
                        var totalQty = product.Quantity;

                        //Đổ dữ liệu vào dòng đầu tiên của sp
                        var packingListEven = new InvoicePackingList();
                        var woEven = lstPackingByProduct.OrderBy(p => p.WO).Select(p => p.WO).ToList();
                        packingListEven.ProductCode = product.ProductCode;
                        packingListEven.ProductName = lstPackingByProduct[0].ProductName;
                        packingListEven.Unit = lstPackingByProduct[0].Unit;
                        packingListEven.CartonQuantity = totalQty > productQtyPerShipBox ? Convert.ToInt32(totalQty) / Convert.ToInt32(productQtyPerShipBox) : 1;
                        packingListEven.Quantity = totalQty > productQtyPerShipBox ? packingListEven.CartonQuantity * productQtyPerShipBox : totalQty;
                        packingListEven.PackageUnit = PackingTypeEnum.Type1;
                        var shipBoxFrameWt = standard.WeightOfShippingBox
                                                    - (standard.QtyPerShippingBox * standard.WeightOfInnerBox);
                        packingListEven.Weight = Math.Round((decimal)(productWt * packingListEven.Quantity + packingListEven.CartonQuantity * shipBoxFrameWt), 0);
                        if (packingListEven.Weight == 0) packingListEven.Weight = 1;
                        packingListEven.Dimension = standard.CartonType.Dimension;

                        lstPackingList.Add(packingListEven);

                        //Nếu sản phẩm còn lẻ ngoài, đóng nốt vào ship box cuối.
                        var ob = totalQty > productQtyPerShipBox ? totalQty % productQtyPerShipBox : 0;
                        if (ob != 0)
                        {
                            //Bản ghi lẻ:
                            var packingListOdd = new InvoicePackingList();
                            var woOdd = new List<string>();
                            packingListOdd.ProductCode = product.ProductCode;
                            packingListOdd.ProductName = lstPackingByProduct[0].ProductName;
                            packingListOdd.Unit = lstPackingByProduct[0].Unit;
                            packingListOdd.CartonQuantity = 1;
                            packingListOdd.PackageUnit = PackingTypeEnum.Type1;
                            packingListOdd.Dimension = standard.CartonType.Dimension;
                            foreach (var pl in lstPackingByProduct)
                            {
                                if (ob <= 0)
                                    break;

                                var effectQty = ob >= pl.Quantity ? pl.Quantity : ob;
                                packingListOdd.Quantity = (packingListOdd.Quantity ?? 0) + effectQty;
                                packingListOdd.Weight = (packingListOdd.Weight ?? 0) + (productWt * effectQty) + shipBoxFrameWt;
                                woOdd.Add(pl.WO);

                                if (ob >= pl.Quantity)//Nếu số dư lớn hơn loại wo này khỏi bản ghi chẵn.
                                {
                                    woEven.Remove(pl.WO);
                                    ob -= pl.Quantity;
                                }
                                else //nếu nhỏ hơn thì giữ nguyên wo trong bản ghi chẵn (vì cả 2 đều dính quantity của nó) và thoát
                                    break;
                            }
                            //Chốt list lẻ
                            packingListOdd.WO = String.Join("\n", woOdd);
                            lstPackingList.Add(packingListOdd);
                        }
                        //Chốt list chẵn
                        packingListEven.WO = String.Join("\n", woEven);
                    }
                    #endregion
                }
                else
                { 
                    #region Đóng gói theo WO

                    #region Tách các product ra thành đống INNER  BOX
                    var lstInnerBox = new List<PackingProduct>();
                    foreach (var product in lstProduct)//Group theo WO
                    {
                        //Thông tin đóng gói
                        var standard = lstPackingStandard.SingleOrDefault(p => p.Product.ProductCode == product.ProductCode);
                        if (standard == null) continue;

                        //Lấy inner chẵn
                        var evenInnerItem = new PackingProduct();
                        evenInnerItem.ProductCode = product.ProductCode;
                        evenInnerItem.WO = product.WO;
                        evenInnerItem.InnerBox = product.Quantity > standard.QtyPerInnerBox
                                                    ? product.Quantity / standard.QtyPerInnerBox.Value : 1;
                        evenInnerItem.Quantity = product.Quantity <= standard.QtyPerInnerBox
                            ? product.Quantity : 
                            evenInnerItem.InnerBox * standard.QtyPerInnerBox.Value;
                        lstInnerBox.Add(evenInnerItem);

                        if (product.Quantity - evenInnerItem.Quantity > 0)
                        {
                            //Lấy inner lẻ
                            var oddInnerItem = new PackingProduct();

                            oddInnerItem.ProductCode = product.ProductCode;
                            oddInnerItem.WO = product.WO;
                            oddInnerItem.InnerBox = 1;
                            oddInnerItem.Quantity = product.Quantity - evenInnerItem.Quantity;

                            lstInnerBox.Add(oddInnerItem);
                        }

                    }
                    #endregion

                    #region Đã có danh sách innerbox, giờ chạy theo từng Product trong danh sách đó để ghép vào thành Box (shipping box)

                    var lstProductByInnerBox = lstInnerBox.Select(p => new { ProductCode = p.ProductCode, InnerQty = p.InnerBox, Quantity = p.Quantity})
                        .GroupBy(p => p.ProductCode, (key, g) => new { ProductCode = key, InnerQty = g.Sum(x => x.InnerQty), Quantity = g.Sum(x=>x.Quantity) });

                    foreach (var product in lstProductByInnerBox)
                    {
                        #region Tính toán từng sản phẩm
                        //chi tiết sản phẩm
                        var productInfo = db.Products.FirstOrDefault(p => p.ProductCode == product.ProductCode);
                        if (productInfo == null) continue;

                        //Thông tin đóng gói
                        var standard = lstPackingStandard.SingleOrDefault(p => p.Product.ProductCode == product.ProductCode);
                        if (standard == null) continue;

                        //Lấy danh sách thông tin theo mặt hàng, xếp từ bé > lớn
                        var lstPackingByProduct = new List<PackingProduct>();
                        var lstPackingByInnerExeption = new List<PackingProduct>();

                        foreach (var item in lstInnerBox.Where(p => p.ProductCode == product.ProductCode)
                            .OrderBy(p => p.InnerBox)
                            .OrderBy(p => p.Quantity).ToList())
                        {
                            if (item.Quantity >= standard.QtyPerInnerBox)
                                lstPackingByProduct.Add(item);
                            else
                                lstPackingByInnerExeption.Add(item);
                        }

                        //Tổng lượng inner
                        var totalEvenInner = lstPackingByProduct.Sum(p => p.InnerBox);

                        //Đổ dữ liệu vào dòng chẵn
                        var woEven = lstPackingByProduct.OrderBy(p => p.WO).Select(p => p.WO).ToList();
                        if (totalEvenInner > 0)
                        {
                            var packingListEven = new InvoicePackingList();
                            packingListEven.ProductCode = product.ProductCode;
                            packingListEven.ProductName = productInfo.ProductName;
                            packingListEven.Unit = productInfo.Unit.UnitName;
                            packingListEven.WO = String.Join("\n", woEven.Distinct());
                            packingListEven.CartonQuantity = totalEvenInner > standard.QtyPerShippingBox ? totalEvenInner / standard.QtyPerShippingBox.Value : 1;
                            packingListEven.Quantity = totalEvenInner > standard.QtyPerShippingBox 
                                ? packingListEven.CartonQuantity * standard.QtyPerShippingBox * standard.QtyPerInnerBox
                                : totalEvenInner * standard.QtyPerInnerBox;
                            //totalEvenInner * standard.QtyPerInnerBox;
                            packingListEven.InnerQuantity = totalEvenInner > standard.QtyPerShippingBox ? packingListEven.CartonQuantity * standard.QtyPerShippingBox : totalEvenInner;
                            packingListEven.PackageUnit = PackingTypeEnum.Type1;
                            packingListEven.Dimension = standard.CartonType.Dimension;

                            lstPackingList.Add(packingListEven);
                        }

                        //Inner full nhưng lẻ ngoài shippingbox
                        var ob = totalEvenInner > standard.QtyPerShippingBox ? totalEvenInner % standard.QtyPerShippingBox : 0;
                        if (ob != 0)
                        {
                            //Bản ghi lẻ:
                            var packingListOdd = new InvoicePackingList();
                            var woOdd = new List<string>();
                            packingListOdd.ProductCode = product.ProductCode;
                            packingListOdd.ProductName = productInfo.ProductName;
                            packingListOdd.Unit = productInfo.Unit.UnitName;
                            packingListOdd.CartonQuantity = 1;
                            packingListOdd.PackageUnit = PackingTypeEnum.Type1;
                            packingListOdd.Dimension = standard.CartonType.Dimension;
                            foreach (var pl in lstPackingByProduct)
                            {
                                if (ob <= 0)
                                    break;

                                var effectInner = ob >= pl.InnerBox ? pl.InnerBox : ob;
                                packingListOdd.InnerQuantity = (packingListOdd.InnerQuantity ?? 0) + effectInner;
                                var effectQty = ob >= pl.InnerBox ? pl.Quantity : (ob * standard.QtyPerInnerBox);
                                packingListOdd.Quantity = (packingListOdd.Quantity ?? 0) + effectQty;
                                if (!woOdd.Contains(pl.WO))
                                    woOdd.Add(pl.WO);

                                if (ob >= pl.InnerBox)//Nếu số dư lớn hơn loại wo này khỏi bản ghi chẵn.
                                {
                                    woEven.Remove(pl.WO);
                                    ob -= pl.InnerBox;
                                }
                                else //nếu nhỏ hơn thì giữ nguyên wo trong bản ghi chẵn (vì cả 2 đều dính quantity của nó) và thoát
                                    break;
                            }
                            //Nếu dòng lẻ vẫn còn thừa chỗ cho innerbox thì đưa các inner ko full vào
                            var removeList = new List<PackingProduct>();
                            foreach (var item in lstPackingByInnerExeption)
                            {
                                woOdd.Add(item.WO);
                                packingListOdd.InnerQuantity = (packingListOdd.InnerQuantity ?? 0) + item.InnerBox;
                                packingListOdd.Quantity = (packingListOdd.Quantity ?? 0) + item.Quantity;
                                removeList.Add(item);
                            }
                            foreach (var item in removeList)
                                lstPackingByInnerExeption.Remove(item);

                            //Chốt list lẻ
                            packingListOdd.WO = String.Join("\n", woOdd.Distinct());
                            lstPackingList.Add(packingListOdd);
                        }

                        //Inner đóng không full
                        lstPackingByInnerExeption = lstPackingByInnerExeption.OrderByDescending(p => p.Quantity).ToList();
                        var packingInnerExep = new InvoicePackingList();
                        var woExep = new List<string>();
                        var count = 0;
                        foreach (var item in lstPackingByInnerExeption)
                        {
                            count++;
                            if (packingInnerExep.ProductCode == null)
                            {
                                packingInnerExep.ProductCode = product.ProductCode;
                                packingInnerExep.ProductName = productInfo.ProductName;
                                packingInnerExep.Unit = productInfo.Unit.UnitName;
                                packingInnerExep.PackageUnit = PackingTypeEnum.Type1;
                                packingInnerExep.Dimension = standard.CartonType.Dimension;
                            }
                            woExep.Add(item.WO);
                            packingInnerExep.InnerQuantity = (packingInnerExep.InnerQuantity ?? 0) + item.InnerBox;
                            packingInnerExep.Quantity = (packingInnerExep.Quantity ?? 0) + item.Quantity;

                            if((packingInnerExep.InnerQuantity ?? 0) == standard.QtyPerShippingBox
                                || count == lstPackingByInnerExeption.Count)
                            {
                                packingInnerExep.CartonQuantity = 1;
                                packingInnerExep.WO = String.Join("\n", woExep.Distinct());
                                lstPackingList.Add(packingInnerExep);
                                packingInnerExep = new InvoicePackingList();
                                woExep = new List<string>();
                            }
                        }

                        #endregion
                    }

                    #endregion

                    #endregion
                }

                #region Tính số thứ tự box
                decimal startIndex = 1;
                decimal nextIndex = 0;
                foreach (var item in lstPackingList)
                {
                    nextIndex += item.CartonQuantity.Value;
                    item.PackageNo = startIndex == nextIndex ? nextIndex.ToString() : String.Format("{0} - {1}", startIndex, nextIndex);
                    startIndex = nextIndex + 1;
                }
                #endregion

                #region Tính lại các thông tin Weight
                foreach (var item in lstPackingList)
                {
                    #region Tính trọng lượng từng hàng
                    var packingStandard = lstPackingStandard.SingleOrDefault(p => p.Product.ProductCode == item.ProductCode);
                    var productQtyPerShipBox = packingStandard.QtyPerInnerBox * packingStandard.QtyPerShippingBox;
                    var shipBoxFrameWt = packingStandard.WeightOfShippingBox
                                                - (packingStandard.QtyPerShippingBox * packingStandard.WeightOfInnerBox);
                    var productWt = packingStandard.WeightOfInnerBox / packingStandard.QtyPerInnerBox;
                    #endregion

                    item.Weight = Math.Round((decimal)(productWt * item.Quantity + item.CartonQuantity * shipBoxFrameWt), 0);
                    if (item.Weight == 0) item.Weight = 1;
                }
                #endregion

                #endregion

                #region Chia ra theo pallet & mix
                if (!chkPLTypeCarton.IsChecked)
                {
                    //Tiêu chuẩn pallet
                    var palletStd = sourcePalletStandard.Current as PalletStandard;

                    //Tổng số box:
                    var totalCarton = (int)(lstPackingList.Sum(p => p.CartonQuantity) ?? 0);

                    //Khởi tạo 2 list Pallet chẵn và lẻ
                    var lstPalletEven = new List<InvoicePackingList>();
                    var lstPalletOdd = new List<InvoicePackingList>();

                    //Sắp xếp lại danh sách list carton để chuẩn bị chia pallet
                    lstPackingList = lstPackingList.OrderBy(p => p.CartonQuantity)
                        .ThenBy(p=>p.Quantity)
                        .ToList();

                    //Số pallet chẵn:
                    var totalPalletEven = totalCarton > palletStd.QtyPerPallet ? totalCarton / palletStd.QtyPerPallet : 1;
                    //Số carton đóng cái đống chẵn này
                    var totalCartonEven = totalPalletEven * palletStd.QtyPerPallet;
                    //Số lẻ ra
                    var totalCartonOdd = totalCarton - totalCartonEven;

                    #region Pallet
                    if (chkPLTypePallet.IsChecked)
                    {
                        #region Gán thông tin pallet
                        foreach (var item in lstPackingList)
                        {
                            item.PackageUnit = PackingTypeEnum.Type2;
                            item.Dimension = palletStd.Dimension;

                            if (totalCartonOdd <= 0)
                            {//Nếu số dư đã hết thì nạp vào chẵn
                                item.PackageNo = totalPalletEven == 1 ? "1" : String.Format("1-{0}", totalPalletEven);
                                item.PalletQuantity = totalPalletEven;
                                lstPalletEven.Add(item.Clone());
                            }
                            else
                            {//chưa hết thì tiếp tục trừ vào lẻ
                                if (totalCartonOdd >= item.CartonQuantity)
                                //Nếu item này nằm trọn trong phần dư thì thêm ngay vào list lẻ
                                {
                                    item.PackageNo = (totalPalletEven + 1).ToString();
                                    item.PalletQuantity = 1;
                                    lstPalletOdd.Add(item.Clone());
                                }
                                else
                                //Nếu item này có số carton > số dư tức là nó nằm giữa cả lst chẵn và lẻ
                                {
                                    var itemEven = item.Clone();
                                    var itemOdd = item.Clone();
                                    //lẻ
                                    itemOdd.Quantity = (itemOdd.Quantity / itemOdd.CartonQuantity) * totalCartonOdd;
                                    itemOdd.CartonQuantity = totalCartonOdd;
                                    itemOdd.PackageNo = (totalPalletEven + 1).ToString();
                                    itemOdd.PalletQuantity = 1;
                                    lstPalletOdd.Add(itemOdd);
                                    //chẵn
                                    itemEven.Quantity = item.Quantity - itemOdd.Quantity;
                                    itemEven.CartonQuantity = item.CartonQuantity - itemOdd.CartonQuantity;
                                    itemEven.PackageNo = totalPalletEven == 1 ? "1" : String.Format("1-{0}", totalPalletEven);
                                    itemEven.PalletQuantity = totalPalletEven;
                                    lstPalletEven.Add(itemEven);
                                }
                            }
                            totalCartonOdd -= item.CartonQuantity;
                        }
                        #endregion

                        #region Tính lại các thông tin WO, Weight
                        foreach (var item in lstPalletEven)
                        {
                            #region Tính trọng lượng từng hàng
                            var packingStandard = lstPackingStandard.SingleOrDefault(p => p.Product.ProductCode == item.ProductCode);
                            var productQtyPerShipBox = packingStandard.QtyPerInnerBox * packingStandard.QtyPerShippingBox;
                            var shipBoxFrameWt = packingStandard.WeightOfShippingBox
                                                        - (packingStandard.QtyPerShippingBox * packingStandard.WeightOfInnerBox);
                            var productWt = packingStandard.WeightOfInnerBox / packingStandard.QtyPerInnerBox;
                            #endregion

                            item.Weight = Math.Round((decimal)(productWt * item.Quantity + item.CartonQuantity * shipBoxFrameWt), 0);
                            if (item.Weight == 0) item.Weight = 1;
                        }
                        var totalPalletListEvenWt = lstPalletEven.Sum(p => p.Weight) + palletStd.PalletWeight;
                        foreach (var item in lstPalletEven)
                            item.Weight = totalPalletListEvenWt;

                        foreach (var item in lstPalletOdd)
                        {
                            #region Tính trọng lượng từng hàng
                            var packingStandard = lstPackingStandard.SingleOrDefault(p => p.Product.ProductCode == item.ProductCode);
                            var productQtyPerShipBox = packingStandard.QtyPerInnerBox * packingStandard.QtyPerShippingBox;
                            var shipBoxFrameWt = packingStandard.WeightOfShippingBox
                                                        - (packingStandard.QtyPerShippingBox * packingStandard.WeightOfInnerBox);
                            var productWt = packingStandard.WeightOfInnerBox / packingStandard.QtyPerInnerBox;
                            #endregion

                            item.Weight = Math.Round((decimal)(productWt * item.Quantity + item.CartonQuantity * shipBoxFrameWt), 0);
                            if (item.Weight == 0) item.Weight = 1;
                        }
                        var totalPalletListOddWt = lstPalletOdd.Sum(p => p.Weight) + palletStd.PalletWeight;
                        foreach (var item in lstPalletOdd)
                            item.Weight = totalPalletListOddWt;
                        #endregion
                    }
                    #endregion

                    #region Mix
                    if (chkPLTypeMix.IsChecked)
                    {
                        #region Gán thông tin mix
                        foreach (var item in lstPackingList)
                        {
                            //Thông tin hàng:
                            var productStd = lstPackingStandard.FirstOrDefault(p => p.Product.ProductCode == item.ProductCode);

                            item.PackageUnit = PackingTypeEnum.Type2;
                            item.Dimension = palletStd.Dimension;

                            if (totalCartonOdd <= 0)
                            {//Nếu số dư đã hết thì nạp vào chẵn
                                item.PalletQuantity = totalPalletEven;
                                item.PackageNo = totalPalletEven == 1 ? "1" : String.Format("1-{0}", totalPalletEven);
                                lstPalletEven.Add(item.Clone());
                            }
                            else
                            {//chưa hết thì tiếp tục trừ vào lẻ
                                if (totalCartonOdd >= item.CartonQuantity)
                                //Nếu item này nằm trọn trong phần dư thì thêm ngay vào list lẻ
                                {
                                    item.PalletQuantity = item.CartonQuantity;
                                    item.PackageUnit = PackingTypeEnum.Type1;
                                    item.Dimension = productStd.CartonType.Dimension;
                                    lstPalletOdd.Add(item.Clone());
                                }
                                else
                                //Nếu item này có số carton > số dư tức là nó nằm giữa cả lst chẵn và lẻ
                                {
                                    var itemEven = item.Clone();
                                    var itemOdd = item.Clone();
                                    //lẻ
                                    itemOdd.Quantity = (itemEven.Quantity / itemEven.CartonQuantity) * totalCartonOdd;
                                    itemOdd.CartonQuantity = totalCartonOdd;
                                    itemOdd.PalletQuantity = totalCartonOdd;
                                    itemOdd.PackageUnit = PackingTypeEnum.Type1;
                                    itemOdd.Dimension = productStd.CartonType.Dimension;
                                    lstPalletOdd.Add(itemOdd);
                                    //chẵn
                                    itemEven.Quantity = item.Quantity - itemOdd.Quantity;
                                    itemEven.CartonQuantity = item.CartonQuantity - itemOdd.CartonQuantity;
                                    itemEven.PalletQuantity = totalPalletEven;
                                    itemEven.PackageNo = totalPalletEven == 1 ? "1" : String.Format("1-{0}", totalPalletEven);
                                    lstPalletEven.Add(itemEven);
                                }
                            }
                            totalCartonOdd -= item.CartonQuantity;
                        }
                        #endregion

                        #region Tính số thứ tự box carton
                        if (chkPLTypeMix.IsChecked)
                        {
                            startIndex = (totalPalletEven ?? 0) + 1;
                            nextIndex = (totalPalletEven ?? 0);
                            foreach (var item in lstPalletOdd)
                            {
                                nextIndex += item.PalletQuantity.Value;
                                item.PackageNo = startIndex == nextIndex ? nextIndex.ToString() : String.Format("{0} - {1}", startIndex, nextIndex);
                                startIndex = nextIndex + 1;
                            }
                        }
                        #endregion

                        #region Tính lại các thông tin WO, Weight
                        foreach (var item in lstPalletEven)
                        {
                            #region Tính trọng lượng từng hàng
                            var packingStandard = lstPackingStandard.SingleOrDefault(p => p.Product.ProductCode == item.ProductCode);
                            var productQtyPerShipBox = packingStandard.QtyPerInnerBox * packingStandard.QtyPerShippingBox;
                            var shipBoxFrameWt = packingStandard.WeightOfShippingBox
                                                        - (packingStandard.QtyPerShippingBox * packingStandard.WeightOfInnerBox);
                            var productWt = packingStandard.WeightOfInnerBox / packingStandard.QtyPerInnerBox;
                            #endregion

                            item.Weight = Math.Round((decimal)(productWt * item.Quantity + item.CartonQuantity * shipBoxFrameWt), 0);
                            if (item.Weight == 0) item.Weight = 1;
                        }
                        var totalPalletListEvenWt = lstPalletEven.Sum(p => p.Weight) + palletStd.PalletWeight;
                        foreach (var item in lstPalletEven)
                            item.Weight = totalPalletListEvenWt;

                        foreach (var item in lstPalletOdd)
                        {
                            #region Tính trọng lượng từng hàng
                            var packingStandard = lstPackingStandard.SingleOrDefault(p => p.Product.ProductCode == item.ProductCode);
                            var productQtyPerShipBox = packingStandard.QtyPerInnerBox * packingStandard.QtyPerShippingBox;
                            var shipBoxFrameWt = packingStandard.WeightOfShippingBox
                                                        - (packingStandard.QtyPerShippingBox * packingStandard.WeightOfInnerBox);
                            var productWt = packingStandard.WeightOfInnerBox / packingStandard.QtyPerInnerBox;
                            #endregion

                            item.Weight = Math.Round((decimal)(productWt * item.Quantity + item.CartonQuantity * shipBoxFrameWt), 0);
                            if (item.Weight == 0) item.Weight = 1;
                        }
                        #endregion
                    }
                    #endregion

                    //Gán lại danh sách
                    lstPackingList.Clear();
                    lstPackingList.AddRange(lstPalletEven);
                    lstPackingList.AddRange(lstPalletOdd);

                    //Sắp xếp lại cho đẹp
                    lstPackingList = lstPackingList.OrderBy(p => p.PackageNo)
                        .ThenBy(p => p.ProductCode)
                        .ThenBy(p => p.WO)
                        .ThenByDescending(p =>p.CartonQuantity)
                        .ThenByDescending(p => p.Quantity)
                        .ToList();
                }
                #endregion

                sourceInvoidePL.DataSource = lstPackingList;
                Common.SetNo(grvInvoicePL);
                #endregion

                Common.ShowDoneMess("Tính xong!");
            }
            catch (Exception ex)
            {
                Common.ShowErrorMess("btnCalculateInvoice_Click - " + ex.Message);
            }
        }

        private void cboBillTo_KeyDown(object sender, KeyEventArgs e)
        {
            try
            {
                if (e.KeyCode == Keys.Enter)
                {
                    var selectedItem = new ShipAddress();
                    var itemId = 0;
                    if (int.TryParse(cboBillTo.Text.Trim(), out itemId))
                        selectedItem = (sourceBillTo.DataSource as List<ShipAddress>).SingleOrDefault(p => p.ShipAddressId == itemId);
                    else
                        selectedItem = (sourceBillTo.DataSource as List<ShipAddress>).FirstOrDefault(p => p.Name.Contains(cboBillTo.Text.Trim()));

                    if (selectedItem != null)
                        cboBillTo.SelectedValue = selectedItem.ShipAddressId;
                    else
                        cboBillTo.SelectedIndex = 0;
                }
            }
            catch (Exception ex)
            {
                Common.ShowErrorMess("cboProduct_KeyDown - " + ex.Message);
            }
        }

        private void cboShipTo_KeyDown(object sender, KeyEventArgs e)
        {
            try
            {
                if (e.KeyCode == Keys.Enter)
                {
                    var selectedItem = new ShipAddress();
                    var itemId = 0;
                    if (int.TryParse(cboShipTo.Text.Trim(), out itemId))
                        selectedItem = (sourceShipTo.DataSource as List<ShipAddress>).SingleOrDefault(p => p.ShipAddressId == itemId);
                    else
                        selectedItem = (sourceShipTo.DataSource as List<ShipAddress>).FirstOrDefault(p => p.Name.Contains(cboShipTo.Text.Trim()));

                    if (selectedItem != null)
                        cboShipTo.SelectedValue = selectedItem.ShipAddressId;
                    else
                        cboShipTo.SelectedIndex = 0;
                }
            }
            catch (Exception ex)
            {
                Common.ShowErrorMess("cboProduct_KeyDown - " + ex.Message);
            }
        }

        private void cboBillTo_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                var currentShipAdd = sourceBillTo.Current as ShipAddress;
                txtBillToName.Text = currentShipAdd.Name;
                txtBillToAddress.Text = currentShipAdd.Address;
                txtBillToPhone.Text = currentShipAdd.Phone;
                txtBillToFax.Text = currentShipAdd.Fax;
            }
            catch (Exception ex)
            {
                Common.ShowErrorMess("cboBillTo_SelectedIndexChanged - " + ex.Message);
            }
        }

        private void cboShipTo_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                var currentShipAdd = sourceShipTo.Current as ShipAddress;
                txtShipToName.Text = currentShipAdd.Name;
                txtShipToAddress.Text = currentShipAdd.Address;
                txtShipToPhone.Text = currentShipAdd.Phone;
                txtShipToFax.Text = currentShipAdd.Fax;

                if (sourceShippingRequest.Count > 0)
                {
                    Common.ShowNoticeMess("Do địa chỉ nhận thay đổi nên các thông tin hóa đơn/đóng gói sẽ được reset");
                    sourceShippingRequest.Clear();
                    sourceInvoiceDetail.Clear();
                    sourceInvoidePL.Clear();
                }
            }
            catch (Exception ex)
            {
                Common.ShowErrorMess("cboShipTo_SelectedIndexChanged - " + ex.Message);
            }
        }

        private void cboShipAccount_SelectedIndexChanged(object sender, EventArgs e)
        {
            var currentAcc = sourceShipAccount.Current as ShipAccount;
            if (currentAcc.ShipViaId != null)
                cboShipVia.SelectedValue = currentAcc.ShipViaId;
        }

        private void cboInvoiceNoIndex_ValueChanged(object sender, EventArgs e)
        {
            txtInvoiceNo.Text = String.Format("{0}{1}", IdPrefix, cboInvoiceNoIndex.Value.ToString().PadLeft(5, '0'));
        }
        
        private void chkPLTypeCarton_ToggleStateChanged(object sender, Telerik.WinControls.UI.StateChangedEventArgs args)
        {
            cboPalletStandard.Visible = (chkPLTypePallet.IsChecked || chkPLTypeMix.IsChecked);
        }

        private void chkAllowModify_ToggleStateChanged(object sender, Telerik.WinControls.UI.StateChangedEventArgs args)
        {
            grvInvoiceDetail.AllowEditRow = grvInvoiceDetail.AllowAddNewRow = grvInvoiceDetail.AllowDeleteRow =
                grvInvoicePL.AllowEditRow = grvInvoicePL.AllowAddNewRow = grvInvoicePL.AllowDeleteRow =
                grvInvoiceDetail.Columns["RowUp"].IsVisible = grvInvoiceDetail.Columns["RowDown"].IsVisible =
                grvInvoicePL.Columns["RowUp"].IsVisible = grvInvoicePL.Columns["RowDown"].IsVisible = 
                args.ToggleState == Telerik.WinControls.Enumerations.ToggleState.On;
        }

        private void grvInvoiceDetail_CellValueChanged(object sender, Telerik.WinControls.UI.GridViewCellEventArgs e)
        {
            try
            {
                grvInvoiceDetail.CellValueChanged -= grvInvoiceDetail_CellValueChanged;
                if (e.Column.Name.Equals("WO"))
                {
                    var listShippingRequest = sourceShippingRequest.DataSource as List<ShippingRequest>;
                    var sr = listShippingRequest.FirstOrDefault(p => p.WorldOrder.WO == Convert.ToString(e.Value));
                    if (sr != null)
                    {
                        e.Row.Cells["PO"].Value = sr.WorldOrder.PO;
                        e.Row.Cells["ProductCode"].Value = sr.WorldOrder.Product.ProductCode;
                        e.Row.Cells["ProductName"].Value = sr.WorldOrder.Product.ProductName;
                        e.Row.Cells["Unit"].Value = sr.WorldOrder.Product.Unit.UnitName;
                        e.Row.Cells["Quantity"].Value = (e.Row.Cells["Quantity"].Value ?? 0);
                        e.Row.Cells["Price"].Value = sr.WorldOrder.Product.Cost;
                        e.Row.Cells["Amount"].Value = (e.Row.Cells["Amount"].Value ?? 0);
                        e.Row.Cells["UhanCodeUsing"].Value = sr.WorldOrder.Product.UhanCodeUsing;
                    }
                    else
                    {
                        Common.ShowNoticeMess("Không tồn tại WO từ các Shipping request đã chọn!");
                        grvInvoiceDetail.MasterView.TableAddNewRow.CancelAddNewRow();
                    }
                }
                else
                {//Nếu nhập những cái khác thì phải yêu cầu có WO mới cho tiếp
                    if (e.Row.Cells["WO"].Value == null)
                    {
                        Common.ShowNoticeMess("Chọn WO trước!");
                        grvInvoiceDetail.MasterView.TableAddNewRow.CancelAddNewRow();
                        grvInvoiceDetail.CellValueChanged += grvInvoiceDetail_CellValueChanged;
                        return;
                    }

                    if (e.Column.Name.Equals("Quantity"))
                    {
                        e.Row.Cells["Quantity"].Value = (e.Row.Cells["Quantity"].Value ?? 0);
                        e.Row.Cells["Amount"].Value = Convert.ToDecimal(e.Row.Cells["Price"].Value) * Convert.ToDecimal(e.Row.Cells["Quantity"].Value);
                    }
                }
                grvInvoiceDetail.CellValueChanged += grvInvoiceDetail_CellValueChanged;
            }
            catch (Exception ex)
            {
                Common.ShowErrorMess("grvInvoiceDetail_CellValueChanged - " + ex.Message);
                grvInvoiceDetail.CellValueChanged += grvInvoiceDetail_CellValueChanged;
            }
        }

        private void grvInvoiceDetail_CommandCellClick(object sender, EventArgs e)
        {
            try
            {
                var command = sender as GridCommandCellElement;
                //Lấy index dòng đang muốn move
                var rowIndex = command.RowIndex;
                if (rowIndex < 0)
                    return;
                //Index của dòng bị hoán đổi
                var moveIndex = 0;
                if (command.ColumnInfo.Name == "RowUp")
                {
                    if (rowIndex == 0)
                        return;
                    moveIndex = rowIndex - 1;
                }
                else if (command.ColumnInfo.Name == "RowDown")
                {
                    if (rowIndex == sourceInvoiceDetail.Count - 1)
                        return;
                    moveIndex = rowIndex + 1;
                }

                //Lấy giá trị của các dòng
                var currentItem = (sourceInvoiceDetail[rowIndex] as InvoiceDetail).Clone();
                var moveItem = (sourceInvoiceDetail[moveIndex] as InvoiceDetail).Clone();

                //Hoán đổi cho nhau
                sourceInvoiceDetail[rowIndex] = moveItem;
                sourceInvoiceDetail[moveIndex] = currentItem;
            }
            catch (Exception ex)
            {
                db.Transaction.Rollback();
                Common.ShowErrorMess("grvInvoiceDetail_CommandCellClick - " + ex.Message);
            }
        }

        private void grvInvoicePL_CellValueChanged(object sender, Telerik.WinControls.UI.GridViewCellEventArgs e)
        {
            try
            {
                grvInvoicePL.CellValueChanged -= grvInvoicePL_CellValueChanged;
                if (e.Column.Name.Equals("WO"))
                {
                    var listShippingRequest = sourceShippingRequest.DataSource as List<ShippingRequest>;
                    var sr = listShippingRequest.FirstOrDefault(p => p.WorldOrder.WO == Convert.ToString(e.Value));
                    if (sr != null)
                    {
                        e.Row.Cells["ProductCode"].Value = sr.WorldOrder.Product.ProductCode;
                        e.Row.Cells["ProductName"].Value = sr.WorldOrder.Product.ProductName;
                        e.Row.Cells["Unit"].Value = sr.WorldOrder.Product.Unit.UnitName;
                        e.Row.Cells["Quantity"].Value = (e.Row.Cells["Quantity"].Value ?? 0);
                        e.Row.Cells["CartonQuantity"].Value = (e.Row.Cells["CartonQuantity"].Value ?? 0);
                        e.Row.Cells["PalletQuantity"].Value = (e.Row.Cells["PalletQuantity"].Value ?? 0);
                        e.Row.Cells["PackageUnit"].Value = chkPLTypeCarton.IsChecked ? PackingTypeEnum.Type1 : PackingTypeEnum.Type2;
                        e.Row.Cells["PackageNo"].Value = "1";
                        e.Row.Cells["Weight"].Value = (e.Row.Cells["Weight"].Value ?? 0);
                        e.Row.Cells["Dimension"].Value = "? x ? x ?";
                    }
                    else
                    {
                        Common.ShowNoticeMess("Không tồn tại WO từ các Shipping request đã chọn!");
                        grvInvoicePL.MasterView.TableAddNewRow.CancelAddNewRow();
                    }
                }
                else
                {//Nếu nhập những cái khác thì phải yêu cầu có WO mới cho tiếp
                    if (e.Row.Cells["WO"].Value == null)
                    {
                        Common.ShowNoticeMess("Chọn WO trước!");
                        grvInvoicePL.MasterView.TableAddNewRow.CancelAddNewRow();
                        grvInvoicePL.CellValueChanged += grvInvoicePL_CellValueChanged;
                        return;
                    }

                    if (e.Column.Name.Equals("Quantity"))
                        e.Row.Cells["Quantity"].Value = (e.Row.Cells["Quantity"].Value ?? 0);
                    if (e.Column.Name.Equals("CartonQuantity"))
                        e.Row.Cells["CartonQuantity"].Value = (e.Row.Cells["CartonQuantity"].Value ?? 0);
                    if (e.Column.Name.Equals("PalletQuantity"))
                        e.Row.Cells["PalletQuantity"].Value = (e.Row.Cells["PalletQuantity"].Value ?? 0);
                    if (e.Column.Name.Equals("PackageUnit"))
                    {
                        var punit = Convert.ToString(e.Value);
                        if (punit != PackingTypeEnum.Type1 && punit != PackingTypeEnum.Type2)
                        {
                            Common.ShowNoticeMess(String.Format("Đơn vị hoặc '{0}' hoặc '{1}'!", PackingTypeEnum.Type1, PackingTypeEnum.Type2));
                            e.Row.Cells["PackageUnit"].Value = PackingTypeEnum.Type1;
                            grvInvoicePL.MasterView.TableAddNewRow.CancelAddNewRow();
                            grvInvoicePL.CellValueChanged += grvInvoicePL_CellValueChanged;
                            return;
                        }
                    }
                    if (e.Column.Name.Equals("PackageNo") && String.IsNullOrEmpty(e.Value.ToString()))
                    {
                        Common.ShowNoticeMess("Số package không để trống!");
                        e.Row.Cells["PackageNo"].Value = "1";
                        grvInvoicePL.MasterView.TableAddNewRow.CancelAddNewRow();
                        grvInvoicePL.CellValueChanged += grvInvoicePL_CellValueChanged;
                        return;
                    }
                    if (e.Column.Name.Equals("Weight"))
                        e.Row.Cells["Weight"].Value = (e.Row.Cells["Weight"].Value ?? 0);
                    if (e.Column.Name.Equals("Dimension") && String.IsNullOrEmpty(e.Value.ToString()))
                    {
                        Common.ShowNoticeMess("Kích thước không để trống!");
                        e.Row.Cells["Dimension"].Value = "? x ? x ?";
                        grvInvoicePL.MasterView.TableAddNewRow.CancelAddNewRow();
                        grvInvoicePL.CellValueChanged += grvInvoicePL_CellValueChanged;
                        return;
                    }
                }
                grvInvoicePL.CellValueChanged += grvInvoicePL_CellValueChanged;
            }
            catch (Exception ex)
            {
                Common.ShowErrorMess("grvInvoicePL_CellValueChanged - " + ex.Message);
                grvInvoicePL.CellValueChanged += grvInvoicePL_CellValueChanged;
            }
        }

        private void grvInvoicePL_CommandCellClick(object sender, EventArgs e)
        {
            try
            {
                var command = sender as GridCommandCellElement;
                //Lấy index dòng đang muốn move
                var rowIndex = command.RowIndex;
                if (rowIndex < 0)
                    return;
                //Index của dòng bị hoán đổi
                var moveIndex = 0;
                if (command.ColumnInfo.Name == "RowUp")
                {
                    if (rowIndex == 0)
                        return;
                    moveIndex = rowIndex - 1;
                }
                else if (command.ColumnInfo.Name == "RowDown")
                {
                    if (rowIndex == sourceInvoidePL.Count - 1)
                        return;
                    moveIndex = rowIndex + 1;
                }

                //Lấy giá trị của các dòng
                var currentItem = (sourceInvoidePL[rowIndex] as InvoicePackingList).Clone();
                var moveItem = (sourceInvoidePL[moveIndex] as InvoicePackingList).Clone();

                //Hoán đổi cho nhau
                sourceInvoidePL[rowIndex] = moveItem;
                sourceInvoidePL[moveIndex] = currentItem;
            }
            catch (Exception ex)
            {
                db.Transaction.Rollback();
                Common.ShowErrorMess("grvInvoicePL_CommandCellClick - " + ex.Message);
            }
        }

        #endregion
    }

    public class PackingProduct
    {
        public string ProductCode { get; set; }
        public string WO { get; set; }
        public int Quantity { get; set; }
        public int InnerBox { get; set; }
    }
}
